#include <future>
#include <iostream>
#include <thread>
#include <vector>

class Vehicle {
  public:
    Vehicle(int id) : _id(id) {}

  private:
    int _id;
};

class WaitingVehicles {
  public:
    WaitingVehicles() : _tmpVehicles(0) {}

    // getters / setters
    void printSize() { std::cout << "#vehicles = " << _tmpVehicles << std::endl; }

    // typical behaviour methods
    void pushBack(Vehicle &&v) {
      //_vehicles.push_back(std::move(v)); // data race would cause an exception
      int oldNum = _tmpVehicles;
      std::this_thread::sleep_for(std::chrono::microseconds(
          1));  // wait deliberately to expose the data race
      _tmpVehicles = oldNum + 1;
    }

  private:
    std::vector<Vehicle>
        _vehicles;  // list of all vehicles waiting to enter this intersection
    int _tmpVehicles;
};

int main() {
  std::shared_ptr<WaitingVehicles> queue(new WaitingVehicles);
  std::vector<std::future<void>> futures;

  for (int i = 0; i < 1000; ++i) {
    Vehicle v(i);
    futures.emplace_back(std::async(
        std::launch::async, &WaitingVehicles::pushBack, queue, std::move(v)));
  }

  for (std::future<void> &ftr : futures) { 
    ftr.wait(); 
  }

  queue->printSize();

  return 0;
}
